#ifndef GL_H
#define GL_H

#include "common.h"

#define Alpha 1
#define NotAlpha 0

int debug_alpha_surface(SDL_Surface* img)
{
    int x, y;
    unsigned int pixel, a;
    static int count = 1;
    char buffer[64];
    unsigned int * pixels;
    
    pixels = img->pixels;
    for(y = 0; y < img->h; ++y)
    {
        for(x = 0; x < img->w; ++x) 
        {
            pixel = pixels[x+y*img->w];
            a = (pixel >> 24) & 255;
            a = 255 - a;
            pixel = a | (a << 8) | (a << 16) | (a << 24);
            pixels[x+y*img->w] = pixel;
        }
    }
    sprintf(buffer, "./debug/debug%d.bmp", count++);
    SDL_SaveBMP(img, buffer);
    return 1;
}

int gl_texture_alpha(SDL_Surface* img)
{
    /*img->format->BytesPerPixel*/
    /*gluBuild2DMipmaps(GL_TEXTURE_2D, 4, img->w, img->h,
        GL_BGRA_EXT, GL_UNSIGNED_BYTE, img->pixels);*/
        
    glTexImage2D(GL_TEXTURE_2D, 0, 
        4, img->w, img->h, 
        0, GL_RGBA, GL_UNSIGNED_BYTE, img->pixels);
    debug_alpha_surface(img);
    return 1;
}

int gl_texture(SDL_Surface* img)
{
    glTexImage2D(GL_TEXTURE_2D, 0, 
        3, img->w, img->h, 
        0, GL_RGB, GL_UNSIGNED_BYTE, img->pixels);
    return 1;
}

typedef struct COLOR_BGR {
    unsigned char b, g, r;
} ColorBGR, *ColorBGR_P;

typedef struct COLOR_RGB {
    unsigned char r, g, b;
} ColorRGB, *ColorRGB_P;

int correct_image_not_alpha(SDL_Surface* img)
{
    ColorBGR_P pixels;
    ColorBGR bad;
    ColorRGB good;
    int x, y;
    
    pixels = img->pixels;
    for(y = 0; y < img->h; ++y)
    {
        for(x = 0; x < img->w; ++x)
        {
            bad = pixels[x+y*img->w];
            good.r = bad.b;
            good.b = bad.r;
            bad.b = good.b;
            bad.r = good.r;
            pixels[x+y*img->w] = bad;
        }
    }
    return 1;
}

typedef struct COLOR_BGRA {
    unsigned char b, g, r, a;
} ColorBGRA, *ColorBGRA_P;

typedef struct COLOR_RGBA {
    unsigned char r, g, b, a;
} ColorRGBA, *ColorRGBA_P;

int correct_image_alpha(SDL_Surface* img)
{
    ColorBGRA_P pixels;
    int x, y;
    ColorBGRA bad;
    ColorRGBA good;

    pixels = img->pixels;
    for(y = 0; y < img->h; ++y)
    {
        for(x = 0; x < img->w; ++x) 
        {
            bad = pixels[x+y*img->w];
            good.r = bad.b;
            good.b = bad.r;
            bad.b = good.b;
            bad.r = good.r;
            pixels[x+y*img->w] = bad;
        }
    }
    return 1;
}

int mirror_image_not_alpha(SDL_Surface* img)
{
    int x, y;
    ColorRGB_P pixels;
    ColorRGB_P src_pixels;
    pixels = malloc(sizeof(ColorRGB)*img->w*img->h);
    src_pixels = img->pixels;
    for(y = 0; y < img->h; ++y)
    {
        for(x = 0; x < img->w; ++x)
        {
            pixels[x+y*img->w] = 
                src_pixels[x+(img->h-y-1)*img->w];
        }
    }
    for(y = 0; y < img->h; ++y)
    {
        for(x = 0; x < img->w; ++x)
        {
            src_pixels[x+y*img->w] = pixels[x+y*img->w];
        }
    }
    free(pixels);
    return 1;
}

int mirror_image_alpha(SDL_Surface* img)
{
    int x, y;
    ColorRGBA_P pixels;
    ColorRGBA_P src_pixels;
    pixels = malloc(sizeof(ColorRGBA)*img->w*img->h);
    src_pixels = img->pixels;
    for(y = 0; y < img->h; ++y)
    {
        for(x = 0; x < img->w; ++x)
        {
            pixels[x+y*img->w] = 
                src_pixels[x+(img->h-y-1)*img->w];
        }
    }
    for(y = 0; y < img->h; ++y)
    {
        for(x = 0; x < img->w; ++x)
        {
            src_pixels[x+y*img->w] = pixels[x+y*img->w];
        }
    }
    free(pixels);
    return 1;
}

SDL_Surface* load_image_to_surface(const char* path, 
    int mode)
{
    SDL_Surface * img;
    img = IMG_Load(path);
    if(!img)
        sdl_error();
    
    SDL_LockSurface(img);
    if(mode == Alpha) {
        correct_image_alpha(img);
        mirror_image_alpha(img);
    } else {
        correct_image_not_alpha(img);
        mirror_image_not_alpha(img);
    }
    SDL_UnlockSurface(img);
    return img;
}

int setup_gl_texture(int* texture, SDL_Surface* img, 
    int mode)
{
    glGenTextures(1, texture);
    glBindTexture(GL_TEXTURE_2D, *texture);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, 
        GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, 
        GL_LINEAR);
        
    SDL_LockSurface(img);
    if(mode == Alpha) {
        gl_texture_alpha(img);
    } else {
        gl_texture(img);
    }
    SDL_UnlockSurface(img);
    return 1;
}

int load_image(int* texture, const char* path, int mode)
{
    SDL_Surface* img;
    img = load_image_to_surface(path, mode);
    setup_gl_texture(texture, img, mode);
    SDL_FreeSurface(img);
    return 1;
}

unsigned int make_rgb(unsigned int r, unsigned int g, 
    unsigned int b)
{
    return (r<<16) | (g<<8) | (b); ////////
}

#endif
